home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / DefaultTableColumnModel.java < prev    next >
Text File  |  1998-06-30  |  18KB  |  581 lines

  1. /*
  2.  * @(#)DefaultTableColumnModel.java    1.18 98/04/07
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21. package com.sun.java.swing.table;
  22.  
  23. import com.sun.java.swing.*;
  24. import com.sun.java.swing.event.*;
  25. import java.awt.*;
  26. import java.util.Vector;
  27. import java.util.Enumeration;
  28. import java.beans.PropertyChangeListener;
  29. import java.beans.PropertyChangeEvent;
  30. import java.io.Serializable;
  31.  
  32. /**
  33.  * The standard column-handler for a JTable.
  34.  * <p>
  35.  * Warning: serialized objects of this class will not be compatible with
  36.  * future swing releases.  The current serialization support is appropriate
  37.  * for short term storage or RMI between Swing1.0 applications.  It will
  38.  * not be possible to load serialized Swing1.0 objects with future releases
  39.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  40.  * baseline for the serialized form of Swing objects.
  41.  *
  42.  * @version 1.18 04/07/98
  43.  * @author Alan Chung
  44.  * @author Philip Milne
  45.  * @see JTable
  46.  */
  47. public class DefaultTableColumnModel implements TableColumnModel,
  48.             PropertyChangeListener, ListSelectionListener, Serializable
  49. {
  50. //
  51. // Instance Variables
  52. //
  53.  
  54.     /** Array of TableColumn objects in this model */
  55.     protected Vector tableColumns;
  56.  
  57.     /** Model for keeping track of column selections */
  58.     protected ListSelectionModel selectionModel;
  59.  
  60.     /** Width margin between each column */
  61.     protected int columnMargin;
  62.  
  63.     /** List of TableColumnModelListener */
  64.     protected EventListenerList listenerList = new EventListenerList();
  65.  
  66.     /** Change event (only one needed) */
  67.     transient protected ChangeEvent changeEvent = null;
  68.  
  69.     /** Column selection allowed in this column model */
  70.     protected boolean columnSelectionAllowed;
  71.  
  72.     /** A local cache of the combined width of all columns */
  73.     protected int totalColumnWidth;
  74.  
  75. //
  76. // Constructors
  77. //
  78.  
  79.     public DefaultTableColumnModel() {
  80.     super();
  81.  
  82.     // Initialize local ivars to default
  83.     tableColumns = new Vector();
  84.     setSelectionModel(createSelectionModel());
  85.     setColumnMargin(1);
  86.     setColumnSelectionAllowed(true);
  87.     }
  88.  
  89. //
  90. // Modifying the model
  91. //
  92.  
  93.     /**
  94.      *  Appends <I>aColumn</I> to the end of the receiver's tableColumns array.
  95.      *  This method also posts the columnAdded() event to its listeners.
  96.      *
  97.      * @param    column        The <B>TableColumn</B> to be added
  98.      * @exception IllegalArgumentException    if <I>aColumn</I> is null
  99.      * @see    #removeColumn()
  100.      */
  101.     public void addColumn(TableColumn aColumn) {
  102.     if (aColumn == null) {
  103.         throw new IllegalArgumentException("Object is null");
  104.     }
  105.  
  106.     tableColumns.addElement(aColumn);
  107.     aColumn.addPropertyChangeListener(this);
  108.     recalcWidthCache();
  109.  
  110.     // Post columnAdded event notification
  111.     fireColumnAdded(new TableColumnModelEvent(this, 0,
  112.                           getColumnCount() - 1));
  113.     }
  114.  
  115.     /**
  116.      *  Deletes the <B>TableColumn</B> <I>column</I> from the
  117.      *  receiver's table columns array.  This method will do nothing if
  118.      *  <I>column</I> is not in the table's columns list.  tile() is called
  119.      *  to resize both the header and table views.
  120.      *  This method also posts the columnRemoved() event to its listeners.
  121.      *
  122.      * @param    column        The <B>TableColumn</B> to be removed
  123.      * @see    #addColumn()
  124.      */
  125.     public void removeColumn(TableColumn column) {
  126.     int columnIndex = tableColumns.indexOf(column);
  127.  
  128.     if (columnIndex != -1) {
  129.         // Adjust for the selection
  130.         if (selectionModel != null)
  131.         selectionModel.removeIndexInterval(columnIndex,columnIndex);
  132.  
  133.         column.removePropertyChangeListener(this);
  134.         tableColumns.removeElementAt(columnIndex);
  135.         recalcWidthCache();
  136.  
  137.         // Post columnAdded event notification.  (JTable and JTableHeader
  138.         // listens so they can adjust size and redraw)
  139.         fireColumnRemoved(new TableColumnModelEvent(this,
  140.                        getColumnCount() - 1, 0));
  141.     }
  142.     }
  143.  
  144.     /**
  145.      * Moves the column and heading at <I>columnIndex</I> to <I>newIndex</I>.
  146.      * The old column at <I>columnIndex</I> will now be found at <I>newIndex</I>,
  147.      * The column that used to be at <I>newIndex</I> is shifted left or right
  148.      * to make room.
  149.      * This will not move any columns if <I>columnIndex</I> equals <I>newIndex</I>.
  150.      * This method also posts the columnMoved() event to its listeners.
  151.      *
  152.      * @param    columnIndex            the index of column to be moved
  153.      * @param    newIndex            New index to move the column
  154.      * @exception IllegalArgumentException    if <I>column</I> or
  155.      *                         <I>newIndex</I>
  156.      *                        are not in the valid range
  157.      */
  158.     public void moveColumn(int columnIndex, int newIndex) {
  159.     if ((columnIndex < 0) || (columnIndex >= getColumnCount()) ||
  160.         (newIndex < 0) || (newIndex >= getColumnCount()))
  161.         throw new IllegalArgumentException("moveColumn() - Index out of range");
  162.  
  163.     TableColumn aColumn;
  164.  
  165.     // Do nothing if the parameters will result in a no-op move
  166.     if (columnIndex == newIndex)
  167.         return;
  168.  
  169.     aColumn = (TableColumn)tableColumns.elementAt(columnIndex);
  170.  
  171.     boolean reselect = false;
  172.     if (selectionModel.isSelectedIndex(columnIndex)) {
  173.         selectionModel.removeSelectionInterval(columnIndex,columnIndex);
  174.         reselect = true;
  175.     }
  176.     tableColumns.removeElementAt(columnIndex);
  177.     tableColumns.insertElementAt(aColumn, newIndex);
  178.     if (reselect)
  179.         selectionModel.addSelectionInterval(newIndex, newIndex);
  180.  
  181.     // Post columnMoved event notification.  (JTable and JTableHeader
  182.     // listens so they can adjust size and redraw)
  183.     fireColumnMoved(new TableColumnModelEvent(this, columnIndex,
  184.                                    newIndex));
  185.     }
  186.  
  187.     /**
  188.      * Sets the column margin to <I>newMargin</I>.
  189.      * This method also posts the columnMarginChanged() event to its
  190.      * listeners.
  191.      *
  192.      * @param    newMargin        the width margin of the column
  193.      * @see    #getColumnMargin()
  194.      * @see    #getTotalColumnWidth()
  195.      */
  196.     public void setColumnMargin(int newMargin) {
  197.     if (newMargin != columnMargin) {
  198.         columnMargin = newMargin;
  199.         recalcWidthCache();
  200.  
  201.         // Post columnMarginChanged event notification.
  202.         fireColumnMarginChanged();
  203.     }
  204.     }
  205.  
  206. //
  207. // Querying the model
  208. //
  209.  
  210.     /**
  211.      * Returns the number of columns in the receiver's table columns array.
  212.      *
  213.      * @return        the number of columns in the receiver's table columns array
  214.      * @see        #getColumns()
  215.      */
  216.     public int getColumnCount() {
  217.     return tableColumns.size();
  218.     }
  219.  
  220.     /**
  221.      * Returns an Enumeration of all the columns in the model
  222.      */
  223.     public Enumeration getColumns() {
  224.     return tableColumns.elements();
  225.     }
  226.  
  227.     /**
  228.      * Returns the index of the first column in the receiver's
  229.      * columns array whose identifier is equal to <I>identifier</I>,
  230.      * when compared using <I>equals()</I>.
  231.      *
  232.      * @return        the index of the first table column in the receiver's
  233.      *            tableColumns array whose identifier is equal to
  234.      *            <I>identifier</I>, when compared using equals().
  235.      * @param        identifier            the identifier object
  236.      * @exception       IllegalArgumentException    if <I>identifier</I> is null or no TableColumn has this identifier
  237.      * @see        #getColumn()
  238.      */
  239.     public int getColumnIndex(Object identifier) {
  240.     if (identifier == null) {
  241.         throw new IllegalArgumentException("Identifier is null");
  242.     }
  243.  
  244.     Enumeration enumeration = getColumns();
  245.     TableColumn aColumn;
  246.     int index = 0;
  247.  
  248.     while (enumeration.hasMoreElements()) {
  249.         aColumn = (TableColumn)enumeration.nextElement();
  250.         // Compare them this way in case the column's identifier is null.
  251.         if (identifier.equals(aColumn.getIdentifier()))
  252.         return index;
  253.         index++;
  254.     }
  255.     throw new IllegalArgumentException("Identifier not found");
  256.     }
  257.  
  258.     /**
  259.      * Returns the <B>TableColumn</B> object for the column at <I>columnIndex</I>
  260.      *
  261.      * @return    the TableColumn object for the column at <I>columnIndex</I>
  262.      * @param    columnIndex    the index of the column desired
  263.      */
  264.     public TableColumn getColumn(int columnIndex) {
  265.     return (TableColumn)tableColumns.elementAt(columnIndex);
  266.     }
  267.  
  268.     /**
  269.      * Returns the width margin for <B>TableColumn</B>.
  270.      * The default columnMargin is 2.
  271.      *
  272.      * @return    the maximum width for the <B>TableColumn</B>.
  273.      * @see    #setColumnMargin()
  274.      */
  275.     public int getColumnMargin()
  276.     {
  277.     return columnMargin;
  278.     }
  279.  
  280.     /**
  281.      * Returns the index of the column that lies on the <I>xPosition</I>,
  282.      * or -1 if it lies outside the any of the column's bounds.
  283.      *
  284.      * @return    the index of the column or -1 if no column is found
  285.      */
  286.     public int getColumnIndexAtX(int xPosition) {
  287.     int index = 0;
  288.     Point aPoint = new Point(xPosition, 1);
  289.     Rectangle columnRect = new Rectangle(0,0,0,3);
  290.     Enumeration enumeration = getColumns();
  291.  
  292.     while (enumeration.hasMoreElements()) {
  293.         TableColumn aColumn = (TableColumn)enumeration.nextElement();
  294.         columnRect.width = aColumn.getWidth() + columnMargin;
  295.  
  296.         if (columnRect.contains(aPoint))
  297.         return index;
  298.  
  299.         columnRect.x += columnRect.width;
  300.         index++;
  301.     }
  302.     return -1;
  303.     }
  304.  
  305.     public int getTotalColumnWidth() {
  306.     return totalColumnWidth;
  307.     }
  308.  
  309. //
  310. // Selection model
  311. //
  312.  
  313.     /**
  314.      *  Sets the selection model for this TableColumnModel to <I>newModel</I>
  315.      *  and registers with for listner notifications from the new selection
  316.      *  model.  If <I>newModel</I> is null, it means columns are not
  317.      *  selectable.
  318.      *
  319.      * @param    newModel    the new selection model
  320.      * @see    #getSelectionModel()
  321.      */
  322.     public void setSelectionModel(ListSelectionModel newModel) {
  323.     ListSelectionModel oldModel = selectionModel;
  324.  
  325.     if (newModel != oldModel) {
  326.         if (oldModel != null) {
  327.         oldModel.removeListSelectionListener(this);
  328.         }
  329.  
  330.         selectionModel= newModel;
  331.  
  332.         if (newModel != null) {
  333.         newModel.addListSelectionListener(this);
  334.         }
  335.     }
  336.     }
  337.  
  338.     /**
  339.      * Returns the <B>ListSelectionModel</B> that is used to maintain column
  340.      * selection state.
  341.      *
  342.      * @return    the object that provides column selection state.  Or
  343.      *        <B>null</B> if row selection is not allowed.
  344.      * @see    #setSelectionModel()
  345.      */
  346.     public ListSelectionModel getSelectionModel() {
  347.     return selectionModel;
  348.     }
  349.  
  350.     public void setColumnSelectionAllowed(boolean flag) {
  351.     columnSelectionAllowed = flag;
  352.     }
  353.  
  354.     public boolean getColumnSelectionAllowed() {
  355.     return columnSelectionAllowed;
  356.     }
  357.  
  358.     public int[] getSelectedColumns() {
  359.     if (selectionModel != null) {
  360.         int iMin = selectionModel.getMinSelectionIndex();
  361.         int iMax = selectionModel.getMaxSelectionIndex();
  362.  
  363.         if ((iMin == -1) || (iMax == -1)) {
  364.         return new int[0];
  365.         }
  366.  
  367.         int[] rvTmp = new int[1+ (iMax - iMin)];
  368.         int n = 0;
  369.         for(int i = iMin; i <= iMax; i++) {
  370.         if (selectionModel.isSelectedIndex(i)) {
  371.             rvTmp[n++] = i;
  372.         }
  373.         }
  374.         int[] rv = new int[n];
  375.         System.arraycopy(rvTmp, 0, rv, 0, n);
  376.         return rv;
  377.     }
  378.     return  new int[0];
  379.     }
  380.  
  381.     public int getSelectedColumnCount() {
  382.     if (selectionModel != null) {
  383.         int iMin = selectionModel.getMinSelectionIndex();
  384.         int iMax = selectionModel.getMaxSelectionIndex();
  385.         int count = 0;
  386.  
  387.         for(int i = iMin; i <= iMax; i++) {
  388.         if (selectionModel.isSelectedIndex(i)) {
  389.             count++;
  390.         }
  391.         }
  392.         return count;
  393.     }
  394.     return 0;
  395.     }
  396.  
  397. //
  398. // Listener Support Methods
  399. //
  400.  
  401.     public void addColumnModelListener(TableColumnModelListener x) {
  402.     listenerList.add(TableColumnModelListener.class, x);
  403.     }
  404.  
  405.     public void removeColumnModelListener(TableColumnModelListener x) {
  406.     listenerList.remove(TableColumnModelListener.class, x);
  407.     }
  408.  
  409. //
  410. //   Event firing methods
  411. //
  412.  
  413.     /*
  414.      * Notify all listeners that have registered interest for
  415.      * notification on this event type.  The event instance
  416.      * is lazily created using the parameters passed into
  417.      * the fire method.
  418.      * @see EventListenerList
  419.      */
  420.     protected void fireColumnAdded(TableColumnModelEvent e) {
  421.     // Guaranteed to return a non-null array
  422.     Object[] listeners = listenerList.getListenerList();
  423.     // Process the listeners last to first, notifying
  424.     // those that are interested in this event
  425.     for (int i = listeners.length-2; i>=0; i-=2) {
  426.         if (listeners[i]==TableColumnModelListener.class) {
  427.         // Lazily create the event:
  428.         // if (e == null)
  429.         //  e = new ChangeEvent(this);
  430.         ((TableColumnModelListener)listeners[i+1]).
  431.             columnAdded(e);
  432.         }
  433.     }
  434.     }
  435.  
  436.     /*
  437.      * Notify all listeners that have registered interest for
  438.      * notification on this event type.  The event instance
  439.      * is lazily created using the parameters passed into
  440.      * the fire method.
  441.      * @see EventListenerList
  442.      */
  443.     protected void fireColumnRemoved(TableColumnModelEvent e) {
  444.     // Guaranteed to return a non-null array
  445.     Object[] listeners = listenerList.getListenerList();
  446.     // Process the listeners last to first, notifying
  447.     // those that are interested in this event
  448.     for (int i = listeners.length-2; i>=0; i-=2) {
  449.         if (listeners[i]==TableColumnModelListener.class) {
  450.         // Lazily create the event:
  451.         // if (e == null)
  452.         //  e = new ChangeEvent(this);
  453.         ((TableColumnModelListener)listeners[i+1]).
  454.             columnRemoved(e);
  455.         }
  456.     }
  457.     }
  458.  
  459.     /*
  460.      * Notify all listeners that have registered interest for
  461.      * notification on this event type.  The event instance
  462.      * is lazily created using the parameters passed into
  463.      * the fire method.
  464.      * @see EventListenerList
  465.      */
  466.     protected void fireColumnMoved(TableColumnModelEvent e) {
  467.     // Guaranteed to return a non-null array
  468.     Object[] listeners = listenerList.getListenerList();
  469.     // Process the listeners last to first, notifying
  470.     // those that are interested in this event
  471.     for (int i = listeners.length-2; i>=0; i-=2) {
  472.         if (listeners[i]==TableColumnModelListener.class) {
  473.         // Lazily create the event:
  474.         // if (e == null)
  475.         //  e = new ChangeEvent(this);
  476.         ((TableColumnModelListener)listeners[i+1]).
  477.             columnMoved(e);
  478.         }
  479.     }
  480.     }
  481.  
  482.     /*
  483.      * Notify all listeners that have registered interest for
  484.      * notification on this event type.  The event instance
  485.      * is lazily created using the parameters passed into
  486.      * the fire method.
  487.      * @see EventListenerList
  488.      */
  489.     protected void fireColumnSelectionChanged(ListSelectionEvent e) {
  490.     // Guaranteed to return a non-null array
  491.     Object[] listeners = listenerList.getListenerList();
  492.     // Process the listeners last to first, notifying
  493.     // those that are interested in this event
  494.     for (int i = listeners.length-2; i>=0; i-=2) {
  495.         if (listeners[i]==TableColumnModelListener.class) {
  496.         // Lazily create the event:
  497.         // if (e == null)
  498.         //  e = new ChangeEvent(this);
  499.         ((TableColumnModelListener)listeners[i+1]).
  500.             columnSelectionChanged(e);
  501.         }
  502.     }
  503.     }
  504.  
  505.     /*
  506.      * Notify all listeners that have registered interest for
  507.      * notification on this event type.  The event instance
  508.      * is lazily created using the parameters passed into
  509.      * the fire method.
  510.      * @see EventListenerList
  511.      */
  512.     protected void fireColumnMarginChanged() {
  513.     // Guaranteed to return a non-null array
  514.     Object[] listeners = listenerList.getListenerList();
  515.     // Process the listeners last to first, notifying
  516.     // those that are interested in this event
  517.     for (int i = listeners.length-2; i>=0; i-=2) {
  518.         if (listeners[i]==TableColumnModelListener.class) {
  519.         // Lazily create the event:
  520.         if (changeEvent == null)
  521.             changeEvent = new ChangeEvent(this);
  522.         ((TableColumnModelListener)listeners[i+1]).
  523.             columnMarginChanged(changeEvent);
  524.         }
  525.     }
  526.     }
  527.  
  528.  
  529. //
  530. // Implementing the PropertyChangeListener interface
  531. //
  532.  
  533.     // PENDING(alan)
  534.     public void propertyChange(PropertyChangeEvent evt) {
  535.     String name = evt.getPropertyName();
  536.  
  537.     if (TableColumn.COLUMN_WIDTH_PROPERTY.equals(name)) {
  538.         recalcWidthCache();
  539.     }
  540.     else if (TableColumn.HEADER_VALUE_PROPERTY.equals(name) ||
  541.          TableColumn.HEADER_RENDERER_PROPERTY.equals(name)) {
  542.     }
  543.     else if (TableColumn.CELL_RENDERER_PROPERTY.equals(name)) {
  544.     }
  545.     }
  546.  
  547. //
  548. // Implementing ListSelectionListener interface
  549. //
  550.  
  551.     public void valueChanged(ListSelectionEvent e) {
  552.     fireColumnSelectionChanged(e);
  553.     }
  554.  
  555. //
  556. // Protected Methods
  557. //
  558.  
  559.     protected ListSelectionModel createSelectionModel() {
  560.         DefaultListSelectionModel m = new DefaultListSelectionModel();
  561.         // By turning this off we get notified of the minimal range of columns
  562.         // that need to be drawn when the selection changes. This improves
  563.         // redrawing performance considerably during mouseDragged.
  564.         m.setLeadAnchorNotificationEnabled(false);
  565.     return m;
  566.     }
  567.  
  568.     protected void recalcWidthCache() {
  569.     Enumeration enumeration = getColumns();
  570.  
  571.     totalColumnWidth = 0;
  572.  
  573.     while (enumeration.hasMoreElements()) {
  574.         totalColumnWidth += ((TableColumn)enumeration.nextElement()).getWidth() +
  575.                 columnMargin;
  576.     }
  577.     }
  578.  
  579. } // End of class DefaultTableColumnModel
  580.  
  581.